package tt.dz.biz.service.financial;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import tt.dz.biz.annotation.MsLog;
import tt.dz.biz.dao.account.AccountingDAO;
import tt.dz.biz.dao.financial.AccountTransferDAO;
import tt.dz.biz.dao.trade.TradeDAOImpl;
import tt.dz.biz.dao.user.OnlineAccountDAO;
import tt.dz.biz.service.account.AccountDividendSupport;
import tt.dz.biz.service.common.CommonService;
import tt.dz.common.BigDecimalUtil;
import tt.dz.common.BusinessException;
import tt.dz.common.DzConstants;
import tt.dz.common.DzConstants.BizType;
import tt.dz.common.DzConstants.Common;
import tt.dz.common.DzConstants.PayType;
import tt.dz.common.DzConstants.accountAdjustType;
import tt.dz.common.DzConstants.accountTransferState;
import tt.dz.common.DzConstants.accountingState;
import tt.dz.common.DzConstants.borrowOrLoanFlag;
import tt.dz.common.DzConstants.payState;
import tt.dz.common.DzConstants.subjectType;
import tt.dz.common.DzConstants.userType;
import tt.dz.common.DzErrorCode;
import tt.dz.common.DzErrorCode.TranErrorCode;
import tt.dz.common.LogUtil;
import tt.dz.vo.AccountTransferVO;
import tt.dz.vo.MerchAccountDividendVO;
import tt.dz.vo.MerchantSubjectAccVO;
import tt.dz.vo.OnlineAccountVO;
import tt.dz.vo.SubjectVO;
import tt.dz.vo.TranInfoVO;
import tt.dz.vo.TranSubVO;
import tt.dz.webframe.config.CommonBean;
import tt.dz.webframe.config.WebConfigFactory;

@Service("accountTransferService")
public class AccountTransferService
{
  @Resource(name="accountTransferDAO")
  private AccountTransferDAO accountTransferDAO;
  @Resource(name="accountingRuleDAO")
  protected AccountingDAO accountingDAO;
  @Resource(name="tradeDAO")
  private TradeDAOImpl tradeDAO;
  @Resource(name="commonService")
  private CommonService commonService;
  @Resource(name="onlineAccountDAO")
  private OnlineAccountDAO onlineAccountDAO;
  @Resource(name="subjectService")
  private SubjectService subjectService;
  @Value("${merchant.code}")
  private String merchantCode;
  @Value("${account.transfer.service.no}")
  private String accountTransferServiceNo;
  private AccountDividendSupport accountDividendSupport = new AccountDividendSupport();
  
  @MsLog(bizCode="accountTransfer", bizName="划拨", bizType=DzConstants.BizType.BUSINESS)
  public void saveAccountTransfer(AccountTransferVO transferVO)
    throws Exception
  {
    try
    {
      String tradeNo = this.commonService.getTradeNo(String.valueOf(DzConstants.userType.MERCHANT_CUSTOMER.value()), WebConfigFactory.getInstance().getCommonBean().getSysCode());
      Date accountDate = this.commonService.getAccountingDate();
      Date dbTime = this.commonService.getDBCurrentTime();
      
      transferVO.setState(DzConstants.accountTransferState.INIT.value());
      transferVO.setTransferSeq(tradeNo);
      transferVO.setBizType(DzConstants.accountAdjustType.ACCOUNT_TRANSGER.value());
      transferVO.setMerchantCode(this.merchantCode);
      transferVO.setCreatedTime(dbTime);
      transferVO.setAccountingDate(accountDate);
      
      int c = this.accountTransferDAO.inertAccountTransfer(transferVO);
      if (c < 1)
      {
        LogUtil.error("保存划拨记录信息失败异常，参数：transferVO=" + transferVO);
        throw new BusinessException(DzErrorCode.TranErrorCode.SAVE_TRAN_INFO_FAIL.value(), "保存记录失败", "保存记录失败");
      }
      TranInfoVO tranInfo = new TranInfoVO();
      tranInfo.setTradeNo(tradeNo);
      tranInfo.setPayer(this.merchantCode);
      tranInfo.setPayerType(DzConstants.userType.MERCHANT_CUSTOMER.value());
      tranInfo.setOriginalPayer(this.merchantCode);
      tranInfo.setOriginalPayerType(DzConstants.userType.MERCHANT_CUSTOMER.value());
      tranInfo.setPaymentAmount(transferVO.getAmount());
      tranInfo.setReceiver(this.merchantCode);
      tranInfo.setReceiverType(DzConstants.userType.MERCHANT_CUSTOMER.value());
      tranInfo.setServiceNo(this.accountTransferServiceNo);
      tranInfo.setAccountingDate(accountDate);
      tranInfo.setAccountState(DzConstants.accountingState.ACCOUNTED.value());
      tranInfo.setPlatTime(dbTime);
      int n = this.tradeDAO.insertTranInfo(tranInfo);
      if (n != 1)
      {
        LogUtil.error("保存划拨交易信息失败异常，参数：tranInfo=" + tranInfo);
        throw new BusinessException(DzErrorCode.TranErrorCode.SAVE_TRAN_INFO_FAIL.value(), "保存划拨交易信息失败", "保存划拨交易信息失败");
      }
      MerchAccountDividendVO resourceDividendVO = new MerchAccountDividendVO();
      MerchAccountDividendVO targetDividendVO = new MerchAccountDividendVO();
      List<MerchAccountDividendVO> dividendList = new ArrayList(2);
      dividendList.add(resourceDividendVO);
      dividendList.add(targetDividendVO);
      
      MerchantSubjectAccVO resourceAccVO = new MerchantSubjectAccVO();
      MerchantSubjectAccVO targetAccVO = new MerchantSubjectAccVO();
      List<MerchantSubjectAccVO> merchantAcctList = new ArrayList(2);
      merchantAcctList.add(resourceAccVO);
      merchantAcctList.add(targetAccVO);
      

      resourceDividendVO.setMerchantCode(this.merchantCode);
      resourceDividendVO.setMerchantCode1(this.merchantCode);
      resourceDividendVO.setAccountingDate(accountDate);
      resourceDividendVO.setSubSubjectCode(transferVO.getSourceSubjectCode());
      resourceDividendVO.setAmount(transferVO.getAmount());
      resourceDividendVO.setTradeNo(tradeNo);
      resourceDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.LOAN_FLAG.value());
      
      targetDividendVO.setMerchantCode(this.merchantCode);
      targetDividendVO.setMerchantCode1(this.merchantCode);
      targetDividendVO.setAccountingDate(accountDate);
      targetDividendVO.setSubSubjectCode(transferVO.getTargetSubjectCode());
      targetDividendVO.setAmount(transferVO.getAmount());
      targetDividendVO.setTradeNo(tradeNo);
      targetDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
      

      resourceAccVO.setMerchantCode(this.merchantCode);
      resourceAccVO.setSubSubjectCode(transferVO.getSourceSubjectCode());
      resourceAccVO.setAcctBal(BigDecimalUtil.sub(new BigDecimal("0"), transferVO.getAmount()));
      
      targetAccVO.setMerchantCode(this.merchantCode);
      targetAccVO.setSubSubjectCode(transferVO.getTargetSubjectCode());
      targetAccVO.setAcctBal(transferVO.getAmount());
      
      int[] rs = this.accountingDAO.updateMerchantSubjectBalance(merchantAcctList);
      judgeResult(rs, "更新运营商账户余额异常，参数为：merchantAcctList=" + dividendList);
      dividendList = this.accountDividendSupport.mergeMerchAccountDividend(dividendList);
      int[] mc = this.accountingDAO.insertMerchAccountDividend(dividendList);
      judgeResult(mc, "插入分录异常，参数为：dividendList=" + dividendList);
    }
    catch (Exception e)
    {
      LogUtil.error("保存划拨交易信息失败异常，参数：tranInfo=" + transferVO, e);
      throw e;
    }
  }
  
  public List<TranInfoVO> queryTranInfosForRefund(Map param)
    throws Exception
  {
    try
    {
      return this.accountTransferDAO.queryTranInfo(param);
    }
    catch (Exception e)
    {
      LogUtil.error("查询交易信息列表异常", e);
      throw e;
    }
  }
  
  public List<TranSubVO> queryTranSubJrnl(String tradeNo)
    throws Exception
  {
    try
    {
      TranInfoVO tranInfo = new TranInfoVO();
      tranInfo.setTradeNo(tradeNo);
      return this.accountingDAO.queryTranSubList(tranInfo);
    }
    catch (Exception e)
    {
      LogUtil.error("查询交易明细列表异常", e);
      throw e;
    }
  }
  
  public void saveRefundInfo(TranInfoVO tranInfoVO, List<TranSubVO> tranSubVOList)
    throws Exception
  {
    try
    {
      String tradeNo = this.commonService.getTradeNo(String.valueOf(tranInfoVO.getOriginalPayerType()), WebConfigFactory.getInstance().getCommonBean().getSysCode());
      Date platTime = this.commonService.getDBCurrentTime();
      Date accoutingDate = this.commonService.getAccountingDate();
      tranInfoVO.setHasAdjust(DzConstants.Common.ONE);
      tranInfoVO.setAdjustTradeNo(tradeNo);
      int n = this.accountTransferDAO.updateTranInfoForRefund(tranInfoVO);
      if (n < 1) {
        throw new BusinessException("退款交易中，更新原交易信息失败，参数为：tranInfoVO=" + tranInfoVO);
      }
      BigDecimal totalAmount = DzConstants.BIGDECIMAL_ZERO;
      for (TranSubVO tranSubVO : tranSubVOList)
      {
        totalAmount = BigDecimalUtil.add(totalAmount, tranSubVO.getRefundAmount());
        tranSubVO.setPaymentAmount(BigDecimalUtil.sub(DzConstants.BIGDECIMAL_ZERO, tranSubVO.getRefundAmount()));
        tranSubVO.setTradeNo(tradeNo);
        tranSubVO.setSubTradeNo(this.commonService.getSubTradeNo());
      }
      int[] count = this.tradeDAO.batchInsertTranSubInfo(tranSubVOList);
      judgeResult(count, "退款交易中，插入退款交易详情失败，参数为：tranSubVOList=" + tranSubVOList);
      if (DzConstants.PayType.EWALLET_PAY.value().equals(tranInfoVO.getPayTypeCode()))
      {
        OnlineAccountVO onlineVO = new OnlineAccountVO();
        onlineVO.setCardNo(tranInfoVO.getCardNo());
        onlineVO.setAcctBal(totalAmount);
        onlineVO.setLastDate(platTime);
        if (!this.onlineAccountDAO.updateOnlineAccountBal(onlineVO)) {
          throw new BusinessException("修改个人电子钱包账户余额异常，参数为：onlineVO=" + onlineVO);
        }
      }
      tranInfoVO.setTradeNo(tradeNo);
      tranInfoVO.setHasAdjust(DzConstants.Common.ZREO);
      tranInfoVO.setAdjustTradeNo(null);
      tranInfoVO.setOrderNo(null);
      tranInfoVO.setRelatedOrderNo(null);
      tranInfoVO.setPlatTime(platTime);
      tranInfoVO.setAccountingDate(accoutingDate);
      tranInfoVO.setAccountState(DzConstants.accountingState.WAIT_FOR_ACCOUNTING.value());
      tranInfoVO.setPaymentAmount(BigDecimalUtil.sub(DzConstants.BIGDECIMAL_ZERO, totalAmount));
      if (DzConstants.userType.PERSONAL_CUSTOMER.value().equals(tranInfoVO.getOriginalPayerType())) {
        tranInfoVO.setPayStateCode(DzConstants.payState.PAY_SUCCESS.value());
      } else if ((DzConstants.userType.ENTERPRISE_CUSTOMER.value().equals(tranInfoVO.getOriginalPayerType())) || 
        (DzConstants.userType.UNIFIEDPAY_CUSTOMER.value().equals(tranInfoVO.getOriginalPayerType()))) {
        tranInfoVO.setPayStateCode(DzConstants.payState.WAITING_FOR_PAYING.value());
      }
      n = this.tradeDAO.insertTranInfo(tranInfoVO);
      if (n < 1) {
        throw new BusinessException("退款交易中，插入退款交易信息失败，参数为：tranInfoVO=" + tranInfoVO);
      }
    }
    catch (Exception e)
    {
      LogUtil.error("保存退款交易异常，参数为：tranInfoVO=" + tranInfoVO + ",tranSubVOList=" + tranSubVOList, e);
      throw e;
    }
  }
  
  @MsLog(bizCode="adjustAccount", bizName="调账", bizType=DzConstants.BizType.BUSINESS)
  public void saveAdjustAccount(AccountTransferVO transferVO)
    throws Exception
  {
    try
    {
      String tradeNo = this.commonService.getTradeNo(String.valueOf(DzConstants.userType.MERCHANT_CUSTOMER.value()), WebConfigFactory.getInstance().getCommonBean().getSysCode());
      Date accountDate = this.commonService.getAccountingDate();
      Date dbTime = this.commonService.getDBCurrentTime();
      
      transferVO.setState(DzConstants.accountTransferState.INIT.value());
      transferVO.setTransferSeq(tradeNo);
      transferVO.setBizType(DzConstants.accountAdjustType.ACCOUNT_ADJUST.value());
      transferVO.setCreatedTime(dbTime);
      transferVO.setAccountingDate(accountDate);
      
      int c = this.accountTransferDAO.inertAccountTransfer(transferVO);
      if (c < 1)
      {
        LogUtil.error("保存调账记录信息失败异常，参数：transferVO=" + transferVO);
        throw new BusinessException(DzErrorCode.TranErrorCode.SAVE_TRAN_INFO_FAIL.value(), "保存记录失败", "保存记录失败");
      }
      TranInfoVO tranInfo = new TranInfoVO();
      tranInfo.setTradeNo(tradeNo);
      tranInfo.setPayer(transferVO.getMerchantCode());
      tranInfo.setPayerType(DzConstants.userType.MERCHANT_CUSTOMER.value());
      tranInfo.setOriginalPayer(transferVO.getMerchantCode());
      tranInfo.setOriginalPayerType(DzConstants.userType.MERCHANT_CUSTOMER.value());
      tranInfo.setPaymentAmount(transferVO.getAmount());
      tranInfo.setReceiver(transferVO.getMerchantCode());
      tranInfo.setReceiverType(DzConstants.userType.MERCHANT_CUSTOMER.value());
      tranInfo.setServiceNo(this.accountTransferServiceNo);
      tranInfo.setAccountingDate(accountDate);
      tranInfo.setAccountState(DzConstants.accountingState.ACCOUNTED.value());
      tranInfo.setPlatTime(dbTime);
      int n = this.tradeDAO.insertTranInfo(tranInfo);
      if (n != 1)
      {
        LogUtil.error("保存调账交易信息失败异常，参数：tranInfo=" + tranInfo);
        throw new BusinessException(DzErrorCode.TranErrorCode.SAVE_TRAN_INFO_FAIL.value(), "保存调账交易信息失败", "保存调账交易信息失败");
      }
      MerchAccountDividendVO resourceDividendVO = new MerchAccountDividendVO();
      MerchAccountDividendVO targetDividendVO = new MerchAccountDividendVO();
      List<MerchAccountDividendVO> dividendList = new ArrayList(2);
      dividendList.add(resourceDividendVO);
      dividendList.add(targetDividendVO);
      
      MerchantSubjectAccVO resourceAccVO = new MerchantSubjectAccVO();
      MerchantSubjectAccVO targetAccVO = new MerchantSubjectAccVO();
      List<MerchantSubjectAccVO> merchantAcctList = new ArrayList(2);
      merchantAcctList.add(resourceAccVO);
      merchantAcctList.add(targetAccVO);
      
      SubjectVO resourceSubject = this.subjectService.querySubjectByCode(transferVO.getSourceSubjectCode());
      if (DzConstants.subjectType.ASSETS.value().equals(resourceSubject.getSubjectType()))
      {
        if (BigDecimalUtil.compareTo(DzConstants.BIGDECIMAL_ZERO, transferVO.getAmount()) >= 0)
        {
          resourceDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.LOAN_FLAG.value());
          targetDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
          resourceAccVO.setAcctBal(transferVO.getAmount());
          targetAccVO.setAcctBal(transferVO.getAmount());
        }
        else
        {
          resourceDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
          targetDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.LOAN_FLAG.value());
          resourceAccVO.setAcctBal(transferVO.getAmount());
          targetAccVO.setAcctBal(transferVO.getAmount());
        }
      }
      else if (DzConstants.subjectType.LIABILITIES.value().equals(resourceSubject.getSubjectType())) {
        if (BigDecimalUtil.compareTo(DzConstants.BIGDECIMAL_ZERO, transferVO.getAmount()) >= 0)
        {
          resourceDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
          targetDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.LOAN_FLAG.value());
          resourceAccVO.setAcctBal(transferVO.getAmount());
          targetAccVO.setAcctBal(BigDecimalUtil.sub(DzConstants.BIGDECIMAL_ZERO, transferVO.getAmount()));
        }
        else
        {
          resourceDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.LOAN_FLAG.value());
          targetDividendVO.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
          resourceAccVO.setAcctBal(transferVO.getAmount());
          targetAccVO.setAcctBal(BigDecimalUtil.sub(DzConstants.BIGDECIMAL_ZERO, transferVO.getAmount()));
        }
      }
      resourceDividendVO.setMerchantCode(transferVO.getMerchantCode());
      resourceDividendVO.setMerchantCode1(transferVO.getMerchantCode());
      resourceDividendVO.setAccountingDate(accountDate);
      resourceDividendVO.setSubSubjectCode(transferVO.getSourceSubjectCode());
      resourceDividendVO.setAmount(transferVO.getAmount());
      resourceDividendVO.setTradeNo(tradeNo);
      
      targetDividendVO.setMerchantCode(transferVO.getMerchantCode());
      targetDividendVO.setMerchantCode1(transferVO.getMerchantCode());
      targetDividendVO.setAccountingDate(accountDate);
      targetDividendVO.setSubSubjectCode(transferVO.getTargetSubjectCode());
      targetDividendVO.setAmount(transferVO.getAmount());
      targetDividendVO.setTradeNo(tradeNo);
      
      resourceAccVO.setMerchantCode(transferVO.getMerchantCode());
      resourceAccVO.setSubSubjectCode(transferVO.getSourceSubjectCode());
      
      targetAccVO.setMerchantCode(transferVO.getMerchantCode());
      targetAccVO.setSubSubjectCode(transferVO.getTargetSubjectCode());
      
      int[] rs = this.accountingDAO.updateMerchantSubjectBalance(merchantAcctList);
      judgeResult(rs, "更新运营商账户余额异常，参数为：merchantAcctList=" + dividendList);
      
      dividendList = this.accountDividendSupport.mergeMerchAccountDividend(dividendList);
      int[] mc = this.accountingDAO.insertMerchAccountDividend(dividendList);
      judgeResult(mc, "插入分录异常，参数为：dividendList=" + dividendList);
    }
    catch (Exception e)
    {
      LogUtil.error("保存调账交易信息失败异常，参数：tranInfo=" + transferVO, e);
      throw e;
    }
  }
  
  protected void judgeResult(int[] rs, String errorMsg)
    throws BusinessException
  {
    if (null == rs)
    {
      LogUtil.error(errorMsg);
      throw new BusinessException(errorMsg);
    }
    for (int i : rs) {
      if (i == 0)
      {
        LogUtil.error(errorMsg);
        throw new BusinessException(errorMsg);
      }
    }
  }
}
